package server;

import java.io.IOException;
import java.net.BindException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;


import utils.ConnectionList;
import utils.ServerInfo;
import utils.Settings;

/**
 * Main server for all games
 */
public class RPSServer {

	private static final int NUM_OF_PARAMS = 3;
	private static final int INDEX_PARAM_SERVER_PORT = 0;
	private static final int INDEX_PARAM_DB_PORT = 1;
	private static final int INDEX_PARAM_DB_HOST = 2;
	
	private static RPSServer instance;
	
	private int serverPort;
	private int dbPort;
	private String dbHost ;
	/** List of server connection objects. */
	private ConnectionList connections;
	private ServerInfo gameInfo;

	private ConnectionThreadServerToDB dbConn;
	
	private boolean isDbOn = true;
	
	
	/**
	 * Default server constructor.
	 */
	private RPSServer() {
					
		System.out.println ("------------------------------------------------------------------");
		System.out.println ("                RPS   G A M E   S E R V E R");
		System.out.println ("------------------------------------------------------------------");

	}
	
	public static RPSServer getInstance () {
		if (instance == null)
			instance = new RPSServer ();
		return instance;
	}
	
	private void init () {
		this.gameInfo = new ServerInfo();
		this.connections = new ConnectionList();
	}
	public void run () {
		RPSServer server = getInstance();
		ServerSocket listenSocket = null;
		Socket dbSocket = null;
		
		try {
			dbSocket = new Socket (server.dbHost, server.dbPort);  //socket for db
			this.dbConn = new ConnectionThreadServerToDB (dbSocket);
			dbConn.start();
			
			listenSocket = new ServerSocket (serverPort);   // socket for clients
			System.out.println ("RPSServer listening on port" + ": " + serverPort);
			
			while (true) {
				Socket clientSocket = listenSocket.accept ();
				ConnectionThreadRPSServerToClient conn = new ConnectionThreadRPSServerToClient (clientSocket);
                conn.start();
			}
		}
		catch (BindException bindEx) {
			showBindExceptionMessage();
		}
		catch (SocketException socketEx) {
			System.out.println ("Database unavailable. Please try again later.");
		}
		catch (Exception genEx) {
		    genEx.printStackTrace();
		}
		finally {
			try {
				if (listenSocket != null)
				    listenSocket.close();
				
				if (dbConn != null)
				{
					dbConn.stopLoop();
					dbConn.getSocket().close();
				}
				else if (dbSocket != null)
				{
					dbSocket.close();
				}
			}
			catch (IOException ioEx) {
			}
		}
	}
	
	private void showBindExceptionMessage()
	{
		System.out.println ("Already running on port" + ": " + serverPort + ". Exiting...");
	}
	
	
	public void setServerPort (int serverPort) {
		this.serverPort = serverPort;
	}
	
	public int getServerPort () {
		return serverPort;
	}
	
	public ServerInfo getGameInfo () {
		return gameInfo;
	}
	
	
	public static void main (String [] args) {
		
		RPSServer server = getInstance ();

		if (0 == args.length) {
			server.serverPort = Settings.SERVER_PORT;
			server.dbPort = Settings.DB_PORT;
			server.dbHost = Settings.DB_HOST;	
		}
		else if (args.length == NUM_OF_PARAMS) {
			server.serverPort = Integer.parseInt(args[INDEX_PARAM_SERVER_PORT]);
			server.dbPort = Integer.parseInt(args[INDEX_PARAM_DB_PORT]);
			server.dbHost = args[INDEX_PARAM_DB_HOST];
		}
		else
			System.out.println("wrong parameters");

		server.init();
		server.run ();
	}

	public ConnectionList getConnections() {
		return connections;
	}
	public ConnectionThreadServerToDB getDBconn(){
		return dbConn;
	}
	
	public void setDBconn(ConnectionThreadServerToDB conn){
		dbConn = conn;
	}
	
	public int getDbPort() { 
		return dbPort;
	}
	
	public String getDbHost() { 
		return dbHost;
	}
	
	public boolean getDbOn() {
		return isDbOn;
	}
	
	public void setDbOn(boolean value) {
		isDbOn = value;
	}
 }